/*
 *  Copyright 2011 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.opu.db_vdumper.ui.component.tabel.models;

import java.awt.Dimension;
import java.awt.Point;
import org.opu.db_vdumper.ui.component.tabel.PikeViewMethod;
import org.opu.db_vdumper.ui.ViewFactory;
import org.opu.db_vdumper.ui.component.tabel.views.PikeView;
import org.opu.db_vdumper.ui.component.tabel.views.TableView;

/**
 *
 * @author Potochnak Yana
 */
public class ArrowCalculator {

    private Point fromConnect, firstNode, secondNode, toConnect;
    private PikeView pickFrom, pickTo;

    public Point getFirstNode() {
        return firstNode;
    }

    public Point getFromConnect() {
        return fromConnect;
    }

    public PikeView getPickFrom() {
        return pickFrom;
    }

    public PikeView getPickTo() {
        return pickTo;
    }

    public Point getSecondNode() {
        return secondNode;
    }

    public Point getToConnect() {
        return toConnect;
    }

    /**
     *  Return array with two points, where line connected with two views
     * @return array with two points, where line connected with two views
     */
    public void connectionPoint(ArrowModel model, TableView from, TableView to ){
        Pike start = model.getStartPike();
        Pike end = model.getEndPike();
        int minWidth = 3 + start.getLength() + end.getLength();
        ViewFactory factory = ViewFactory.getInstance();
        PikeViewMethod method = factory.getPikeViewMethod();

        pickFrom = method.getNullPikeView(start);
        pickTo = method.getNullPikeView(end);

        Point fromLoc = from.getLocation();
        Point toLoc = to.getLocation();

        Dimension fs = from.getPreferredSize();
        Dimension ts = to.getPreferredSize();
        ts.width -= 2;
        ts.height -= 2;
        fs.width -= 2;
        fs.height -= 2;

        int whereFrom = from.where(model.getFrom().getName()) + fromLoc.y;
        int whereTo = to.where(model.getTo().getName()) + toLoc.y;

        int szl = toLoc.x - minWidth - fromLoc.x - fs.width;
        int szr = toLoc.x + ts.width + minWidth - fromLoc.x;
        if (szl > 0){//to правее from
            //System.out.println("::ArrowView.connectionPoint >");
            int m = szl/2;
            int x = fromLoc.x + fs.width;
            fromConnect = new Point(x, whereFrom);
            firstNode = new Point(x + m, whereFrom);
            secondNode = new Point(x + m, whereTo);
            toConnect = new Point(toLoc.x, whereTo);
            pickTo = method.getLinePikeView(end, PikeView.RIGHT_DIRECTION);
        } else if (szr < 0){//to левее from
            //System.out.println("::ArrowView.connectionPoint <");
            int m = Math.abs(szr/2);
            fromConnect = new Point(fromLoc.x, whereFrom);
            firstNode = new Point(fromLoc.x - m, whereFrom);
            secondNode = new Point(fromLoc.x - m, whereTo);
            toConnect = new Point(toLoc.x + ts.width, whereTo);
            pickTo = method.getLinePikeView(end, PikeView.LEFT_DIRECTION);
        } else {
            int v1 = fromLoc.x - toLoc.x;
            //System.out.println(fromLoc.x + "-" + toLoc.x + "=" + v1);
            if (v1 > v1 + fs.width - ts.width ){//on the right side
                onRight(fromLoc, fs, whereFrom, toLoc, ts, end, start, whereTo);
            } else {//on the left side
                //System.out.println("::ArrowView.connectionPoint <-");
                fromConnect = new Point(fromLoc.x, whereFrom);
                int al = toLoc.x - end.getLength();
                int ar = fromLoc.x - start.getLength();
                int max = Math.min(al, ar);
                if (max < 1) {
                    onRight(fromLoc, fs, whereFrom, toLoc, ts, end, start, whereTo);
                } else {
                    firstNode = new Point(max, whereFrom);
                    secondNode = new Point(max, whereTo);
                    toConnect = new Point(toLoc.x, whereTo);
                    pickTo = method.getLinePikeView(end, PikeView.RIGHT_DIRECTION);
                }
            }
        }

    }
    
    /**on the right side - см. код!*/
    private void onRight(Point fromLoc, Dimension fs, int whereFrom, Point toLoc,
            Dimension ts, Pike end, Pike start, int whereTo) {
        
        ViewFactory factory = ViewFactory.getInstance();
        PikeViewMethod method = factory.getPikeViewMethod();
        //System.out.println("::ArrowView.connectionPoint ->");
        fromConnect = new Point(fromLoc.x + fs.width, whereFrom);
        int al = toLoc.x + ts.width + end.getLength();
        int ar = fromLoc.x + fs.width + start.getLength();
        int max = Math.max(al, ar);
        firstNode = new Point(max, whereFrom);
        secondNode = new Point(max, whereTo);
        toConnect = new Point(toLoc.x + ts.width, whereTo);
        pickTo = method.getLinePikeView(end, PikeView.LEFT_DIRECTION);

    }

    public String pointsStr(ArrowModel model, TableView from, TableView to) {
        String s = "from {" + from.getLocation() + from.getPreferredSize() + "}"
                + "to {"  + to.getLocation() + to.getPreferredSize()  + "} {"
                + fromConnect + "; " + firstNode + "; " + secondNode + "; " + toConnect + "}";
        s = s.replaceAll("java.awt.Point", "").replaceAll("java.awt.Dimension", " ");
        return s;
    }

    /**
     * Return array of border points:(lx, ly, rx, ry)<ol>
     *  <li>the leftmost point</li>
     *  <li>topmost point</li>
     *  <li>topmost point</li>
     *  <li>the lowest point</li></ol>
     * To get View component location use:<pre>
     *      int arr[] = borderPoints;
     *      location = new Point(arr[0], arr[1]);
     * </pre> To get view preferder size use:<pre>
     *      size = new Dimension(arr[2] - arr[0] + 2, arr[3] - arr[1] + 2);
     * </pre>
     * @return
     */
    public int[] borderPoints(){
        int lx = fromConnect.x;
        int rx = fromConnect.x;
        int ly = fromConnect.y;
        int ry = fromConnect.y;

        if (firstNode.x < lx){
            lx = firstNode.x;
        }
        if (secondNode.x < lx){
            lx = secondNode.x;
        }
        if (toConnect.x < lx){
            lx = toConnect.x;
        }

        if (firstNode.x > rx){
            rx = firstNode.x;
        }
        if (secondNode.x > rx){
            rx = secondNode.x;
        }
        if (toConnect.x > rx){
            rx = toConnect.x;
        }

        if (firstNode.y < ly){
            ly = firstNode.y;
        }
        if (secondNode.y < ly){
            ly = secondNode.y;
        }
        if (toConnect.y < ly){
            ly = toConnect.y;
        }

        if (firstNode.y > ry){
            ry = firstNode.y;
        }
        if (secondNode.y > ry){
            ry = secondNode.y;
        }
        if (toConnect.y > ry){
            ry = toConnect.y;
        }

        Point[] points = pickTo.points();
        for (Point p : points) {
            p.x += toConnect.x;
            p.y += toConnect.y;
            if (p.x > rx){
                rx = p.x;
            }
            if (p.x < lx){
                lx = p.x;
            }
            if (p.y > ry){
                ry = p.y;
            }
            if (p.y < ly){
                ly = p.y;
            }
        }

        return new int[]{lx, ly, rx, ry};
        //location = new Point(lx, ly);
        //size = new Dimension(rx - lx + 2, ry - ly + 2);
    }

}
